package roleservicelogic

import (
	"context"
	"fmt"
	"sync" // 导入 sync 包

	"github.com/zeromicro/go-zero/core/stores/sqlx"

	"smile-sunshine-micorservice/rpc/User/db/crud"
	"smile-sunshine-micorservice/rpc/User/internal/svc"
	"smile-sunshine-micorservice/rpc/User/pb/zipTako.com/SmileSunshine/user"

	"github.com/zeromicro/go-zero/core/logx"
)

type AssignRoleLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
	UserRolesModel crud.UserRolesModel
	UsersModel     crud.UsersModel
	RolesModel     crud.RolesModel
}

func NewAssignRoleLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AssignRoleLogic {
	return &AssignRoleLogic{
		ctx:            ctx,
		svcCtx:         svcCtx,
		Logger:         logx.WithContext(ctx),
		UserRolesModel: crud.NewUserRolesModel(svcCtx.SqlConn, svcCtx.CacheConf),
		UsersModel:     crud.NewUsersModel(svcCtx.SqlConn, svcCtx.CacheConf),
		RolesModel:     crud.NewRolesModel(svcCtx.SqlConn, svcCtx.CacheConf),
	}
}

func (l *AssignRoleLogic) AssignRole(in *user.AssignRoleRequest) (*user.AssignRoleResponse, error) {
	l.Logger.Infof("收到分配角色请求，用户ID：%d", in.UserId)

	// 1. 参数验证
	if err := l.validateAssignRoleRequest(in); err != nil {
		return &user.AssignRoleResponse{
			Success: false,
			Message: err.Error(),
		}, nil
	}

	// 2. 检查用户是否存在
	userInfo, err := l.UsersModel.FindOne(l.ctx, in.UserId)
	if err != nil {
		return &user.AssignRoleResponse{
			Success: false,
			Message: "用户不存在",
		}, nil
	}

	// 3. 检查用户是否已被删除
	if userInfo.DeletedAt.Valid == true {
		return &user.AssignRoleResponse{
			Success: false,
			Message: "用户已被删除，无法分配角色",
		}, nil
	}

	// 4. 验证所有角色是否存在且未被删除
	for _, roleId := range in.RoleIds {
		role, err := l.RolesModel.FindOne(l.ctx, roleId)
		if err != nil {
			return &user.AssignRoleResponse{
				Success: false,
				Message: fmt.Sprintf("角色ID %d 不存在", roleId),
			}, nil
		}
		if role.DeletedAt.Valid == true {
			return &user.AssignRoleResponse{
				Success: false,
				Message: fmt.Sprintf("角色 %s 已被删除", role.Name),
			}, nil
		}
	}

	// 5. 开始事务
	err = l.svcCtx.SqlConn.TransactCtx(l.ctx, func(ctx context.Context, session sqlx.Session) error {
		// 5.1 删除用户现有的所有角色
		err := l.UserRolesModel.DeleteByUserId(ctx, in.UserId)
		if err != nil {
			return fmt.Errorf("删除用户现有角色失败：%v", err)
		}

		// 5.2 并发分配新的角色
		var wg sync.WaitGroup
		errChan := make(chan error, len(in.RoleIds)) // 创建带缓冲的错误通道

		for _, roleId := range in.RoleIds {
			wg.Add(1)
			go func(rId int64) {
				defer wg.Done()
				userRole := &crud.UserRoles{
					UserId: in.UserId,
					RoleId: rId,
				}
				_, insertErr := l.UserRolesModel.Insert(ctx, userRole) // 传递 ctx
				if insertErr != nil {
					// 将错误发送到通道，非阻塞
					select {
					case errChan <- fmt.Errorf("分配角色ID %d 失败：%v", rId, insertErr):
					default: // 如果通道已满，避免阻塞
						l.Logger.Errorf("错误通道已满，无法发送错误：%v", insertErr)
					}
				}
			}(roleId)
		}

		// 等待所有 goroutine 完成
		wg.Wait()
		close(errChan) // 关闭通道，以便 range 可以结束

		// 检查是否有错误发生
		for err := range errChan {
			if err != nil {
				return err // 如果有任何错误，返回第一个遇到的错误，触发事务回滚
			}
		}

		return nil
	})

	if err != nil {
		l.Logger.Errorf("分配角色失败：%v", err)
		return &user.AssignRoleResponse{
			Success: false,
			Message: "分配角色失败，请稍后重试",
		}, nil
	}

	// 6. 返回成功响应
	return &user.AssignRoleResponse{
		Success: true,
		Message: "分配角色成功",
	}, nil
}

// validateAssignRoleRequest 验证分配角色请求参数
func (l *AssignRoleLogic) validateAssignRoleRequest(in *user.AssignRoleRequest) error {
	// 验证用户ID
	if in.UserId <= 0 {
		return fmt.Errorf("无效的用户ID")
	}

	// 验证角色ID列表
	if len(in.RoleIds) == 0 {
		return fmt.Errorf("角色ID列表不能为空")
	}

	// 验证角色ID的有效性
	for _, roleId := range in.RoleIds {
		if roleId <= 0 {
			return fmt.Errorf("存在无效的角色ID")
		}
	}

	return nil
}
